
#pragma once

#include "ly/types.hpp"
#include "ly/vec2.hpp"

namespace ly {

template <class C>
class box {
 public:
  // 构造函数
  box() : p1(0, 0), p2(0, 0) {}
  box(C x1, C y1, C x2, C y2) : p1(x1, y1), p2(x2, y2) {}

  // 拷贝构造函数（编译器自动生成，可显式声明）
  box(const box<C>& other) = default;

  // 赋值操作符
  box<C>& operator=(const box<C>& other) = default;

  // 移动构造/赋值（C++11）
  box(box<C>&& other) = default;
  box<C>& operator=(box<C>&& other) = default;

  // --- 基础几何函数 ---
  C width() const { return p2.x - p1.x; }
  C height() const { return p2.y - p1.y; }
  C area() const { return width() * height(); }

  //  求中心点
  point<C> center() const { return point<C>((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); }

  //  判断点是否在 box 内部（含边界）
  bool contains(const point<C>& pt) const {
    // 先确保比较时 p1 <= p2（规范化）
    C min_x = std::min(p1.x, p2.x);
    C max_x = std::max(p1.x, p2.x);
    C min_y = std::min(p1.y, p2.y);
    C max_y = std::max(p1.y, p2.y);

    return pt.x >= min_x && pt.x <= max_x && pt.y >= min_y && pt.y <= max_y;
  }

  // 判断另一个 box 是否完全包含在当前 box 内
  bool contains(const box<C>& other) const { return contains(other.p1) && contains(other.p2); }

  // 是否与另一个 box 相交
  bool intersects(const box<C>& other) const {
    C min_x1 = std::min(p1.x, p2.x), max_x1 = std::max(p1.x, p2.x);
    C min_y1 = std::min(p1.y, p2.y), max_y1 = std::max(p1.y, p2.y);
    C min_x2 = std::min(other.p1.x, other.p2.x), max_x2 = std::max(other.p1.x, other.p2.x);
    C min_y2 = std::min(other.p1.y, other.p2.y), max_y2 = std::max(other.p1.y, other.p2.y);

    return !(max_x1 < min_x2 || max_x2 < min_x1 || max_y1 < min_y2 || max_y2 < min_y1);
  }

  // 规范化：确保 p1 是左下角，p2 是右上角
  box<C> normalized() const {
    C min_x = std::min(p1.x, p2.x);
    C max_x = std::max(p1.x, p2.x);
    C min_y = std::min(p1.y, p2.y);
    C max_y = std::max(p1.y, p2.y);
    return box<C>(min_x, min_y, max_x, max_y);
  }

  // 扩展 box 以包含一个点（返回新 box）
  box<C> merged_with(const point<C>& pt) const {
    box<C> norm = normalized();
    return box<C>(std::min(norm.p1.x, pt.x), std::min(norm.p1.y, pt.y), std::max(norm.p2.x, pt.x), std::max(norm.p2.y, pt.y));
  }

  // 扩展 box 以包含另一个 box
  box<C> merged_with(const box<C>& other) const {
    box<C> norm = normalized();
    box<C> other_norm = other.normalized();
    return box<C>(std::min(norm.p1.x, other_norm.p1.x), std::min(norm.p1.y, other_norm.p1.y), std::max(norm.p2.x, other_norm.p2.x),
                  std::max(norm.p2.y, other_norm.p2.y));
  }

  //  private:
  point<C> p1, p2;
};

// 盒子
typedef box<Coord> Box;

// 盒子数组
typedef std::vector<box<Coord>> Boxs;

// double类型盒子
typedef box<DCoord> DBox;

// double类型盒子数组
typedef std::vector<box<DCoord>> DBoxs;

}  // namespace ly
